package org.example.cml;

import java.io.BufferedReader;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * CPU & 内存占用控制程序（动态波动 + 内存抖动版）
 */
public class RunnerMain {

    static class CMConfig {
        double cpuTarget = 0.3;          // CPU目标占用 0~1
        double cpuFluctuation = 0.1;     // CPU浮动 ±10%
        int cpuIntervalMs = 100;         // CPU调整间隔

        double memoryTarget = 0.6;       // 内存目标占用 0~1
        double memoryFluctuation = 0.05; // 内存波动 ±5%
        int memoryIntervalMs = 500;      // 内存调整间隔
        double memoryJitter = 0.1;       // 内存抖动 ±10%
    }

    private static long[] prevCpuTimes = null;

    private static double getCpuUsage() {
        try (BufferedReader br = new BufferedReader(new FileReader("/proc/stat"))) {
            String line = br.readLine();
            if (line == null || !line.startsWith("cpu ")) return 0.0;

            String[] tokens = line.trim().split("\\s+");
            long user = Long.parseLong(tokens[1]);
            long nice = Long.parseLong(tokens[2]);
            long system = Long.parseLong(tokens[3]);
            long idle = Long.parseLong(tokens[4]);
            long iowait = Long.parseLong(tokens[5]);
            long irq = Long.parseLong(tokens[6]);
            long softirq = Long.parseLong(tokens[7]);

            long idleTime = idle + iowait;
            long totalTime = user + nice + system + idle + iowait + irq + softirq;

            long[] cpuTimes = new long[]{idleTime, totalTime};
            double usage = 0.0;
            if (prevCpuTimes != null) {
                long idleDiff = cpuTimes[0] - prevCpuTimes[0];
                long totalDiff = cpuTimes[1] - prevCpuTimes[1];
                usage = (totalDiff - idleDiff) / (double) totalDiff;
            }
            prevCpuTimes = cpuTimes;
            return usage;
        } catch (Exception e) {
            return 0.0;
        }
    }

    public static void main(String[] args) throws Exception {
        CMConfig config = new CMConfig();
        boolean cpuFlag = true;
        boolean memoryFlag = true;

        for (String arg : args) {
            if (arg.startsWith("--cpu.flag=")) cpuFlag = Boolean.parseBoolean(arg.split("=")[1]);
            if (arg.startsWith("--memory.flag=")) memoryFlag = Boolean.parseBoolean(arg.split("=")[1]);
        }

        int cores = Runtime.getRuntime().availableProcessors();
        System.out.println("CPU 核数: " + cores);

        int blockSizeMB = 10;

        // 读取系统总内存
        long totalMemMB;
        try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
            long memTotalKB = 0;
            String line;
            while ((line = br.readLine()) != null) {
                if (line.startsWith("MemTotal:")) memTotalKB = Long.parseLong(line.replaceAll("\\D+", ""));
            }
            totalMemMB = memTotalKB / 1024;
        }
        System.out.println("系统总内存: " + totalMemMB + " MB");

        int totalBlocks = (int) (totalMemMB * config.memoryTarget / blockSizeMB);
        ByteBuffer[] memoryHolder = new ByteBuffer[totalBlocks];
        System.out.println("最大 Direct Memory 块数: " + totalBlocks);

        Random random = new Random();
        ExecutorService executor = Executors.newCachedThreadPool();

        // CPU 控制线程（动态波动）
        if (cpuFlag) {
            for (int i = 0; i < cores; i++) {
                executor.submit(() -> {
                    while (true) {
                        try {
                            double factor = 1 + (random.nextDouble() * 2 - 1) * config.cpuFluctuation;
                            double usage = Math.min(config.cpuTarget * factor, 1.0);
                            long workTime = (long) (config.cpuIntervalMs * usage);
                            long idleTime = config.cpuIntervalMs - workTime;

                            long start = System.currentTimeMillis();
                            while (System.currentTimeMillis() - start < workTime) {
                                double x = Math.random() * Math.random();
                            }
                            if (idleTime > 0) TimeUnit.MILLISECONDS.sleep(idleTime);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }

        // 内存控制线程（动态波动 + 抖动）
        if (memoryFlag) {
            // 缓慢攀升
            executor.submit(() -> {
                try {
                    long memTotalKB = 0, memAvailableKB = 0;
                    try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
                        String line;
                        while ((line = br.readLine()) != null) {
                            if (line.startsWith("MemTotal:")) memTotalKB = Long.parseLong(line.replaceAll("\\D+", ""));
                            if (line.startsWith("MemAvailable:")) memAvailableKB = Long.parseLong(line.replaceAll("\\D+", ""));
                        }
                    }

                    long totalMemMB2 = memTotalKB / 1024;
                    long freeMemMB = memAvailableKB / 1024;
                    long usedMemMB = totalMemMB2 - freeMemMB;
                    double currentRatio = usedMemMB / (double) totalMemMB2;  // 当前占用比

                    double upperBound = config.memoryTarget + config.memoryFluctuation;
                    double lowerBound = config.memoryTarget - config.memoryFluctuation;
                    boolean increasing = true; // 当前趋势：上升或下降

                    System.out.printf("初始内存使用率：%.2f%%，目标区间：%.2f%% ~ %.2f%%%n",
                                      currentRatio * 100, lowerBound * 100, upperBound * 100);

                    while (true) {
                        try {
                            // 读取实时内存占用
                            long memAvailableKB2 = 0;
                            try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
                                String line;
                                while ((line = br.readLine()) != null) {
                                    if (line.startsWith("MemAvailable:"))
                                        memAvailableKB2 = Long.parseLong(line.replaceAll("\\D+", ""));
                                }
                            }

                            long usedMemMB2 = totalMemMB2 - memAvailableKB2 / 1024;
                            double usedRatio = usedMemMB2 / (double) totalMemMB2;

                            // 趋势控制：随机波动
                            double step = 0.005 + random.nextDouble() * 0.005; // 每次波动 0.5%~1%
                            if (increasing) {
                                currentRatio += step;
                                if (currentRatio >= upperBound) increasing = false; // 到达上限反转
                            } else {
                                currentRatio -= step;
                                if (currentRatio <= lowerBound) increasing = true; // 到达下限反转
                            }

                            // 限制范围
                            currentRatio = Math.max(0.05, Math.min(0.95, currentRatio));

                            int targetBlocks = (int) (totalMemMB2 * currentRatio / blockSizeMB);
                            int currentBlocks = 0;
                            for (ByteBuffer buf : memoryHolder) if (buf != null) currentBlocks++;

                            int diffBlocks = targetBlocks - currentBlocks;

                            if (diffBlocks > 0) {
                                // 增加内存块
                                for (int i = 0; i < diffBlocks; i++) {
                                    for (int j = 0; j < memoryHolder.length; j++) {
                                        if (memoryHolder[j] == null) {
                                            try {
                                                ByteBuffer buf = ByteBuffer.allocateDirect(blockSizeMB * 1024 * 1024);
                                                for (int k = 0; k < buf.capacity(); k += 4096)
                                                    buf.put(k, (byte) 0);
                                                memoryHolder[j] = buf;
                                            } catch (OutOfMemoryError e) {
                                                break;
                                            }
                                            break;
                                        }
                                    }
                                }
                            } else if (diffBlocks < 0) {
                                // 释放内存块
                                for (int i = 0; i < -diffBlocks; i++) {
                                    for (int j = memoryHolder.length - 1; j >= 0; j--) {
                                        if (memoryHolder[j] != null) {
                                            memoryHolder[j] = null;
                                            break;
                                        }
                                    }
                                }
                            }

                            System.out.printf("CPU: %.2f%% | 内存使用: %.2f%% (%d MB / %d MB)%n",
                                              getCpuUsage() * 100, usedRatio * 100, usedMemMB2, totalMemMB2);

                            TimeUnit.MILLISECONDS.sleep(config.memoryIntervalMs);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });

            // 直接攀升 限定范围
            // executor.submit(() -> {
            //     while (true) {
            //         try {
            //             long memTotalKB = 0, memAvailableKB = 0;
            //             try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
            //                 String line;
            //                 while ((line = br.readLine()) != null) {
            //                     if (line.startsWith("MemTotal:")) memTotalKB = Long.parseLong(line.replaceAll("\\D+", ""));
            //                     if (line.startsWith("MemAvailable:")) memAvailableKB = Long.parseLong(line.replaceAll("\\D+", ""));
            //                 }
            //             }
            //
            //             long freeMemMB = memAvailableKB / 1024;
            //             long usedMemMB = totalMemMB - freeMemMB;
            //             double usedRatio = usedMemMB / (double) totalMemMB;
            //
            //             // 目标占用随机抖动
            //             double targetRatio = config.memoryTarget * (1 + (random.nextDouble() * 2 - 1) * config.memoryJitter);
            //
            //             int targetBlocks = (int) (totalMemMB * targetRatio / blockSizeMB);
            //
            //             if (memoryHolder.length < targetBlocks) targetBlocks = memoryHolder.length;
            //
            //             // 调整内存块数量
            //             int currentBlocks = 0;
            //             for (ByteBuffer buf : memoryHolder) if (buf != null) currentBlocks++;
            //
            //             int diffBlocks = targetBlocks - currentBlocks;
            //
            //             if (diffBlocks > 0) {
            //                 for (int i = 0; i < diffBlocks; i++) {
            //                     for (int j = 0; j < memoryHolder.length; j++) {
            //                         if (memoryHolder[j] == null) {
            //                             try {
            //                                 ByteBuffer buf = ByteBuffer.allocateDirect(blockSizeMB * 1024 * 1024);
            //                                 for (int k = 0; k < buf.capacity(); k += 4096) buf.put(k, (byte) 0);
            //                                 memoryHolder[j] = buf;
            //                             } catch (OutOfMemoryError e) {
            //                                 break;
            //                             }
            //                             break;
            //                         }
            //                     }
            //                 }
            //             } else if (diffBlocks < 0) {
            //                 for (int i = 0; i < -diffBlocks; i++) {
            //                     for (int j = memoryHolder.length - 1; j >= 0; j--) {
            //                         if (memoryHolder[j] != null) {
            //                             memoryHolder[j] = null;
            //                             break;
            //                         }
            //                     }
            //                 }
            //             }
            //
            //             System.out.println(String.format(
            //                     "CPU Used: %.2f%% | 系统内存使用: %d MB / %d MB (%.2f%%)",
            //                     getCpuUsage() * 100,
            //                     usedMemMB, totalMemMB, usedRatio * 100
            //                                             ));
            //
            //             TimeUnit.MILLISECONDS.sleep(config.memoryIntervalMs);
            //
            //         } catch (Exception e) {
            //             e.printStackTrace();
            //         }
            //     }
            // });
        }
    }
}
